package com.aliang.shopping.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.aliang.shopping.common.PageResult;
import com.aliang.shopping.common.Result;
import com.aliang.shopping.common.ResultCodeEnum;
import com.aliang.shopping.config.OssConfig;
import com.aliang.shopping.contact.BasicConstant;
import com.aliang.shopping.contact.ResultMsgContact;
import com.aliang.shopping.exception.DataException;
import com.aliang.shopping.exception.ServiceException;
import com.aliang.shopping.log.annotation.OperateLog;
import com.aliang.shopping.log.enums.OperateType;
import com.aliang.shopping.model.converter.AdminConverter;
import com.aliang.shopping.model.dto.admin.AdminImportDTO;
import com.aliang.shopping.model.dto.admin.AdminInsertDTO;
import com.aliang.shopping.model.dto.admin.AdminUpDatePwdDTO;
import com.aliang.shopping.model.dto.admin.AdminUpdateDTO;
import com.aliang.shopping.model.dto.common.PageDTO;
import com.aliang.shopping.model.dto.common.UpdatePasswordDTO;
import com.aliang.shopping.model.dto.common.UpdateStatusDTO;
import com.aliang.shopping.model.po.Admin;
import com.aliang.shopping.model.vo.admin.AdminExportVO;
import com.aliang.shopping.model.vo.admin.AdminVO;
import com.aliang.shopping.security.PreventRepeatSubmit;
import com.aliang.shopping.service.AdminService;
import com.aliang.shopping.util.InputDataUtil;
import com.aliang.shopping.util.PasswordUtil;
import com.aliang.shopping.util.excel.ExcelUtils;
import com.aliang.shopping.util.excel.listener.AdminImportListener;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/admin")
@AllArgsConstructor
public class AdminController {

    private final AdminService adminService;
    private final AdminConverter adminConverter;
    private final ExcelUtils excelUtils;
    private final OssConfig ossConfig;
    /**
     * 管理员插入
     *
     * @param insertDTO
     * @return
     */
    @PostMapping("/insert")
    @ApiOperation("管理员插入")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员插入", type = OperateType.INSERT)
    public Result<String> insertAdmin(@RequestBody AdminInsertDTO insertDTO) {
        //必要字段非空校验
        if (BeanUtil.hasNullField(insertDTO) || StrUtil.hasBlank(insertDTO.getUsername(), insertDTO.getPassword())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        // 密码长度校验
        if (StrUtil.length(insertDTO.getPassword()) < 8) {
            throw new DataException(ResultCodeEnum.PASSWORD_LENGTH_ERR);
        }
        //判断数字是否合法
        if (!InputDataUtil.numIsOK(insertDTO.getSex()) || !InputDataUtil.numIsOK(insertDTO.getTypeNum())) {
            throw new DataException(ResultCodeEnum.TYPE_NUM_ERR);
        }

        // 判断账号唯一
        int count = adminService.count(new QueryWrapper<Admin>().eq("username", insertDTO.getUsername()));
        if (count > 0) {
            throw new ServiceException(ResultCodeEnum.USERNAME_IS_EXIT);
        }
        //如果昵称未设置，设置为账号
        if (StrUtil.isBlank(insertDTO.getNickname())) {
            insertDTO.setNickname(insertDTO.getUsername());
        }
        // 密码加密
        insertDTO.setPassword(PasswordUtil.encrypt(insertDTO.getPassword()));
        // 如果有头像路径，需要截取
        if (StrUtil.isNotBlank(insertDTO.getAvatar())) {
            insertDTO.setAvatar(StrUtil.subAfter(insertDTO.getAvatar(),ossConfig.getUrl(), false));
        }
        //转换数据
        Admin admin = this.adminConverter.toPoByInsertDTO(insertDTO);
        this.adminService.save(admin);
        return Result.ok(ResultMsgContact.INSERT_SUCCESS);
    }

    /**
     * 管理员删除
     *
     * @param ids
     * @return
     */
    @DeleteMapping("/del")
    @ApiOperation("管理员删除")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员删除", type = OperateType.DELETE)
    public Result<String> delAdmin(@RequestBody List<Long> ids) {
        this.adminService.removeByIds(ids);
        return Result.ok(ResultMsgContact.DELETE_SUCCESS);
    }

    /**
     * 管理员更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update")
    @ApiOperation("管理员更改")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员更改", type = OperateType.UPDATE)
    public Result<String> updateAdmin(@RequestBody AdminUpdateDTO updateDTO) {
        //必要字段校验
        if (ObjectUtil.isNull(updateDTO.getId())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        // 如果有头像路径，需要截取
        if (StrUtil.isNotBlank(updateDTO.getAvatar())) {
            updateDTO.setAvatar(StrUtil.subAfter(updateDTO.getAvatar(),ossConfig.getUrl(), false));
        }
        //转换数据
        Admin admin = this.adminConverter.toPoByUpdateDTO(updateDTO);
        this.adminService.updateById(admin);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 管理员状态更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update_static")
    @ApiOperation("管理员状态更改")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员状态更改", type = OperateType.UPDATE)
    public Result<String> updateAdminStatic(@RequestBody UpdateStatusDTO updateDTO) {
        //必要字段校验
        if (BeanUtil.isEmpty(updateDTO)) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        // 状态数字合法性校验
        if (!InputDataUtil.numIsOK(updateDTO.getStatus())) {
            throw new DataException(ResultCodeEnum.TYPE_NUM_ERR);
        }
        //转换数据
        Admin admin = this.adminConverter.toPoByUpdateStaticDTO(updateDTO);
        this.adminService.updateById(admin);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 管理员个人密码修改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update_pwd")
    @ApiOperation("管理员个人密码修改")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员个人密码修改", type = OperateType.UPDATE)
    public Result<String> updateAdminSelfPwd(@RequestBody UpdatePasswordDTO updateDTO) {
        //校验密码
        PasswordUtil.validate(updateDTO);
        //判断账号是否一致
        Admin admin = this.adminService.getOne(new QueryWrapper<Admin>().select("password").eq("id", updateDTO.getId()));
        if (ObjectUtil.isNull(admin)) {
            throw new ServiceException(ResultCodeEnum.USERNAME_IS_NOT_EXIT);
        }
        //判断输入的旧密码与密码是否一致
        if (PasswordUtil.isNotEqual(admin.getPassword(), updateDTO.getOldPassword())) {
            throw new DataException(ResultCodeEnum.OLD_PASSWORD_NOT_WITH);
        }
        //转换数据
        Admin save = this.adminConverter.toPoByUpdatePasswordDTO(updateDTO);
        //保存数据
        this.adminService.updateById(save);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 管理员密码批量修改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update_pwd_batch")
    @ApiOperation("管理员密码批量修改")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员密码批量修改", type = OperateType.UPDATE)
    public Result<String> updateAdminPwdBatch(@RequestBody AdminUpDatePwdDTO updateDTO) {
        //必要字段校验
        if (updateDTO.getIds().isEmpty()) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //如果有设置密码，加密密码
        if (!StrUtil.isBlank(updateDTO.getPassword())) {
            //密码小于8位，抛出异常
            if (StrUtil.length(updateDTO.getPassword()) < 8) {
                throw new DataException(ResultCodeEnum.PASSWORD_LENGTH_ERR);
            }
            updateDTO.setPassword(PasswordUtil.encrypt(updateDTO.getPassword()));
        } else {
            //否则设置默认密码
            updateDTO.setPassword(PasswordUtil.encrypt(BasicConstant.DEFAULT_PASSWORD));
        }
        //批量保存
        List<Admin> adminList = updateDTO.getIds().stream()
                .map(id -> this.adminConverter.toPoByIdWithPwd(id, updateDTO.getPassword()))
                .collect(Collectors.toList());
        this.adminService.updateBatchById(adminList);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 管理员分页搜索
     */
    @GetMapping("/getPage")
    @ApiOperation("管理员分页搜索")
    public Result<PageResult<AdminVO>> queryAdminPage(PageDTO pageDTO) {
        //必要字段校验
        if (ObjectUtil.hasNull(pageDTO.getPageSize(), pageDTO.getPageNum())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //查询数据
        PageResult<AdminVO> result = this.adminService.selectPage(pageDTO);
        return Result.ok(result);
    }

    /**
     * 管理员导入模版下载
     *
     * @param response
     * @throws IOException
     */
    @ApiOperation("管理员导入模版下载")
    @GetMapping("/template")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员导入模版下载", type = OperateType.DOWNLOAD)
    public void downloadAdminTemplate(HttpServletResponse response) throws IOException {
        String fileName = "管理员导入模版.xlsx";
        this.excelUtils.downloadTemplate(response, fileName);
    }

    /**
     * 管理员导入
     */
    @PostMapping("/import")
    @ApiOperation("管理员导入")
    @PreventRepeatSubmit
    @OperateLog(title = "管理员导入", type = OperateType.IMPORT)
    public Result<String> importAdmin(MultipartFile file) throws IOException {
        if (ObjectUtil.isEmpty(file)) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //创建数据导入监听器
        AdminImportListener adminImportListener = new AdminImportListener(adminConverter, adminService);
        String msg = this.excelUtils.importExcel(file.getInputStream(), AdminImportDTO.class, adminImportListener);
        return Result.ok(msg);
    }

    /**
     * 管理员导出
     */
    @ApiOperation("导出管理员信息")
    @GetMapping("/export")
    @PreventRepeatSubmit
    @OperateLog(title = "导出管理员信息", type = OperateType.EXPORT)
    public void exportAdmin(PageDTO pageDTO, HttpServletResponse response) throws IOException {
        String fileName = "管理员列表.xlsx";
        // 设置请求头
        this.excelUtils.setHeader(response, fileName);
        List<AdminExportVO> exportUserList = this.adminService.getExportList(pageDTO);
        //查询数据
        EasyExcel.write(response.getOutputStream(), AdminExportVO.class).sheet("管理员列表")
                .doWrite(exportUserList);
    }
}
